package com.machine.filling.net.ws.network;

import android.util.Log;

import com.machine.filling.util.Common;

import java.util.Calendar;
import java.util.concurrent.TimeUnit;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;
import okio.ByteString;

/**
 * Created by sperfan on 2018/3/1.
 *
 * @描述:
 */

public class WebSocketUtil {
    private static final String TAG = "WebSocketUtil";

    private static WebSocketUtil instance;

    private OkHttpClient client;

    private Request request;

    private WebSocket mWebSocket;
    /**
     * 最大重连次数
     */
    private int maxRetryCount = Integer.MAX_VALUE;
    /**
     * 重连次数
     */
    private int retryCount = 0;
    /**
     * 上次重连时间
     */
    private long lastRetryTimeMillion;
    /**
     * 重连间隔时间
     */
    private long retryIntervalTime = 10 * 1000;
    /**
     * websocket 连接回调
     */
    private IWebSocketCallback iWebSocketCallback;

    /**
     * 获取最大重连次数
     * @return
     */
    public int getMaxRetryCount() {
        return maxRetryCount;
    }

    /**
     * 设置最大重连次数
     * @param maxRetryCount
     */
    public void setMaxRetryCount(int maxRetryCount) {
        this.maxRetryCount = maxRetryCount;
    }

    /**
     * 获取重连间隔时间
     * @return
     */
    public long getRetryIntervalTime() {
        return retryIntervalTime;
    }

    /**
     * 设置重连间隔时间
     * @param retryIntervalTime
     */
    public void setRetryIntervalTime(long retryIntervalTime) {
        this.retryIntervalTime = retryIntervalTime;
    }

    /**
     * 设置websocket连接回调
     * @param iWebSocketCallback
     */
    public void setiWebSocketCallback(IWebSocketCallback iWebSocketCallback) {
        this.iWebSocketCallback = iWebSocketCallback;
    }

    public WebSocketUtil() {

    }

    public static WebSocketUtil getInstance() {
        if (instance == null) {
            synchronized (WebSocketUtil.class) {
                if (instance == null) {
                    instance = new WebSocketUtil();
                }
            }
        }
        return instance;
    }

    /**
     * 初始化 websocket
     *
     * @param token
     * @param machineId
     * @return
     */
    public void initWebSocket(String token, String machineId) {
        if (mWebSocket == null) {
            client = new OkHttpClient.Builder()
                    .readTimeout(5, TimeUnit.SECONDS)
                    .writeTimeout(5, TimeUnit.SECONDS)
                    .connectTimeout(5, TimeUnit.SECONDS)
                    .build();
            request = new Request.Builder()
                    .url(Common.WS_URL_ + token + "/" + machineId)
                    .build();
            Log.d(TAG, "initWebSocket() returned: " + "websocket打开：" + Common.WS_URL_ + token + "/" + machineId);
            mWebSocket = client.newWebSocket(request, webSocketListener);
        }

    }

    private WebSocketListener webSocketListener = new WebSocketListener() {
        @Override
        public void onOpen(WebSocket webSocket, Response response) {
            super.onOpen(webSocket, response);
            Log.d(TAG, "onOpen() returned: " + "websocket 已开启");
            iWebSocketCallback.onOpen(webSocket,response);
        }

        @Override
        public void onMessage(WebSocket webSocket, String text) {
            super.onMessage(webSocket, text);
//            Log.d(TAG, "onMessage() returned: websocket 接收到消息文本==" + text);
            retryCount = 0;
            iWebSocketCallback.onMessage(webSocket,text,null);
        }

        @Override
        public void onMessage(WebSocket webSocket, ByteString bytes) {
            super.onMessage(webSocket, bytes);
            Log.d(TAG, "" + webSocket.request().body()+ "结果返回");
            Log.d(TAG, "onMessage() returned: websocket 接收到消息字节==" + bytes);
            retryCount = 0;
            iWebSocketCallback.onMessage(webSocket,null,bytes);
        }

        @Override
        public void onClosing(WebSocket webSocket, int code, String reason) {
            super.onClosing(webSocket, code, reason);
            Log.d(TAG, "onClosing() returned: websocketOnClosing 正在关闭-->原因:==" + reason);
            //  如果服务器断开,会走这里
//            webSocket.close(1000, null);

        }

        @Override
        public void onClosed(WebSocket webSocket, int code, String reason) {
            super.onClosed(webSocket, code, reason);
            Log.d(TAG, "onClosed() returned: websocketOnClosed: 关闭-->原因==" + reason);
            handleFinalConnectResult(webSocket,code,reason,null);
        }

        @Override
        public void onFailure(WebSocket webSocket, Throwable t, Response response) {
            super.onFailure(webSocket, t, response);
            // TODO: 2018/2/28 此处经常性的会出现EOFException 所以进行重新连接
            Log.d(TAG, "onFailure() returned: websocketOnFailure: 连接失败-->原因:==" + t.toString());
            handleFinalConnectResult(webSocket,4444,t.toString(),response);
        }
    };

    /**
     * 处理最终重连结果
     */
    private void handleFinalConnectResult(WebSocket webSocket, int code, String reason,Response response){
        boolean isRetry = reConnect();
        if (!isRetry){
            //不再继续重连,则通知界面
            iWebSocketCallback.onFinalFailureResult(webSocket,code,reason,response);
        }
    }

    /**
     * 重连
     *
     * @return 返回 是否是最后一次重连  true是 ;false不是,还会继续重连接
     */
    private boolean reConnect() {
        if (mWebSocket == null){
            Log.d(TAG, "reConnect() returned: " + "mWebsocket==null");
            return true;
        }
        Log.d(TAG, "reConnect() returned: " + "重连:第" + retryCount + "次");
        if (retryCount > maxRetryCount) {
            Log.d(TAG, "reConnect() returned: 已经到达最大重连次数" + maxRetryCount);
            // TODO: 2018/3/1 显示重连失败 websocket连接异常 ,保存重连信息.关闭连接
            mWebSocket.close(1000, "重连失败");
            return true;
        } else {
            //如果是第一次重连,直接等待三秒;
            if (retryCount == 0) {
                lastRetryTimeMillion = Calendar.getInstance().getTimeInMillis();
                try {
                    Thread.sleep(retryIntervalTime);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            } else {
                long currentTimeMillion = Calendar.getInstance().getTimeInMillis();
                try {
                    Thread.sleep(retryIntervalTime - (currentTimeMillion - lastRetryTimeMillion) > 0 ? retryIntervalTime - (currentTimeMillion - lastRetryTimeMillion) : 0);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            mWebSocket = client.newWebSocket(request, webSocketListener);
            lastRetryTimeMillion = Calendar.getInstance().getTimeInMillis();
        }
        retryCount++;
        return false;
    }

    /**
     * 关闭websocket 并释放websocket
     */
    public void close(){
        mWebSocket.close(2000,"主动关闭");
        mWebSocket = null;
    }

    public WebSocket getmWebSocket() {
        return mWebSocket;
    }
}
